package com.lry.basic.netty.protocol.codec;

import com.lry.basic.netty.protocol.constant.Constant;
import com.lry.basic.netty.protocol.struct.Header;
import com.lry.basic.netty.protocol.struct.NettyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.io.IOException;
import java.util.Map;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/9/12
 */
public class MsgEncoder extends MessageToByteEncoder<NettyMsg> {
    private MarshallingEncoder marshallingEncoder;
    public MsgEncoder() throws IOException {
        this.marshallingEncoder = new MarshallingEncoder();
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, NettyMsg nettyMsg, ByteBuf buf) throws Exception {
        if(nettyMsg == null || nettyMsg.getHeader() == null){
            throw new Exception("编码失败,没有数据信息!");
        }
        Header header = nettyMsg.getHeader();
        buf.writeInt(header.getCrcCode());
        buf.writeInt(header.getLength());
        buf.writeLong(header.getSessionId());
        buf.writeByte(header.getType());
        buf.writeByte(header.getPriority());

        buf.writeInt(header.getAttachment().size());
        String key = null;
        byte[] keyArray = null;
        Object value = null;
        for(Map.Entry<String,Object> entry:header.getAttachment().entrySet()){
            key = entry.getKey();
            keyArray = key.getBytes(Constant.charset);
            buf.writeInt(keyArray.length);
            buf.writeBytes(keyArray);
            value = entry.getValue();
            marshallingEncoder.encode(value, buf);
        }

        Object body = nettyMsg.getBody();
        if(body!=null){
            marshallingEncoder.encode(body, buf);
        }else{
            //如果没有数据 则进行补位 为了方便后续的 decoder操作
            buf.writeInt(0);
        }

        //最后我们要获取整个数据包的总长度 也就是 header +  body 进行对 header length的设置

        // TODO:  解释： 在这里必须要-8个字节 ，是因为要把CRC和长度本身占的减掉了
        //（官方中给出的是：LengthFieldBasedFrameDecoder中的lengthFieldOffset+lengthFieldLength）
        //总长度是在header协议的第二个标记字段中
        //第一个参数是长度属性的索引位置
        buf.setInt(4, buf.readableBytes() - 8);
    }
}
